{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Estimate the rate of CFO from preamble and preamble convolved"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Input: Preamble, Preamble convolved with AWGN channel\n",
    "Output: rate of CFO\n",
    "\n",
    "\n",
    "Since we can't actually control / measure cfo on real radios, the loss function can only have what we know.\n",
    "\n",
    "Loss: Preamble - Preamble convolved * CFO correction"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0\n",
      "10000\n",
      "20000\n",
      "30000\n",
      "40000\n",
      "50000\n",
      "60000\n",
      "70000\n",
      "80000\n",
      "90000\n",
      "100000\n",
      "110000\n",
      "120000\n",
      "130000\n",
      "140000\n",
      "150000\n",
      "160000\n",
      "170000\n",
      "180000\n",
      "190000\n",
      "200000\n",
      "210000\n",
      "220000\n",
      "230000\n",
      "240000\n",
      "250000\n",
      "260000\n",
      "270000\n",
      "280000\n",
      "290000\n",
      "300000\n",
      "310000\n",
      "320000\n",
      "330000\n",
      "340000\n",
      "350000\n",
      "360000\n",
      "370000\n",
      "380000\n",
      "390000\n",
      "400000\n",
      "410000\n",
      "420000\n",
      "430000\n",
      "440000\n",
      "450000\n",
      "460000\n",
      "470000\n",
      "480000\n",
      "490000\n",
      "500000\n",
      "510000\n",
      "520000\n",
      "530000\n",
      "540000\n",
      "550000\n",
      "560000\n",
      "570000\n",
      "580000\n",
      "590000\n",
      "600000\n",
      "610000\n",
      "620000\n",
      "630000\n",
      "640000\n",
      "650000\n",
      "660000\n",
      "670000\n",
      "680000\n",
      "690000\n",
      "700000\n",
      "710000\n",
      "720000\n",
      "730000\n",
      "740000\n",
      "750000\n",
      "760000\n",
      "770000\n",
      "780000\n",
      "790000\n",
      "800000\n",
      "810000\n",
      "820000\n",
      "830000\n",
      "840000\n",
      "850000\n",
      "860000\n",
      "870000\n",
      "880000\n",
      "890000\n",
      "900000\n",
      "910000\n",
      "920000\n",
      "930000\n",
      "940000\n",
      "950000\n",
      "960000\n",
      "970000\n",
      "980000\n",
      "990000\n",
      "Data generation complete.\n"
     ]
    }
   ],
   "source": [
    "# generate data\n",
    "\n",
    "import numpy as np\n",
    "import scipy.signal as sig\n",
    "from numpy import linalg as LA\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "# Create training and test data for the NN\n",
    "\n",
    "epochs = 10000\n",
    "batch_size = 100\n",
    "\n",
    "snr=50\n",
    "\n",
    "# number of random preambles that will be trained and tested on\n",
    "num_train=epochs*batch_size\n",
    "num_test=batch_size\n",
    "\n",
    "preamble_length = 50\n",
    "\n",
    "# QPSK\n",
    "preamble_train_orig = np.zeros((num_train,preamble_length,2))\n",
    "preamble_train_cfo = np.zeros((num_train,preamble_length,2))\n",
    "preamble_test_orig = np.zeros((num_test,preamble_length,2))\n",
    "preamble_test_cfo = np.zeros((num_test,preamble_length,2))\n",
    "\n",
    "# the max value the CFO rate can be \n",
    "max_omega = 1/50\n",
    "# the cfo rate is in number of radians turned per sample\n",
    "omega_train = np.random.uniform(low=0,high=max_omega, size=((num_train,1)))\n",
    "omega_test = np.random.uniform(low=0,high=max_omega, size=((num_test,1)))\n",
    "\n",
    "\n",
    "for i in range(num_train):\n",
    "    # original preamble - known to both TX and RX\n",
    "    preamble_train_orig[i,:,:] = ((2*np.random.randint(2,size=(preamble_length,2)))-1)*np.sqrt(2)/2\n",
    "    # add AWG noise to the preamble\n",
    "    if snr > 0:\n",
    "        preamble_noisy = (1./np.sqrt(snr)) * np.random.randn(preamble_length,2)+preamble_train_orig[i,:,:]\n",
    "    \n",
    "    # rotate data according to cfo\n",
    "    for j in range(preamble_length):\n",
    "        preamble_train_cfo[i,j,0]=(preamble_noisy[j,0]*np.cos(omega_train[i]*j)\n",
    "                                       -preamble_noisy[j,1]*np.sin(omega_train[i]*j))\n",
    "        preamble_train_cfo[i,j,1]=(preamble_noisy[j,0]*np.sin(omega_train[i]*j)\n",
    "                                      +preamble_noisy[j,1]*np.cos(omega_train[i]*j))\n",
    "    \n",
    "    if i % 10000 == 0:\n",
    "        print(i)\n",
    "    \n",
    "\n",
    "for i in range(0, num_test):\n",
    "    # original preamble - known to both TX and RX\n",
    "    preamble_test_orig[i,:,:] = ((2*np.random.randint(2,size=(preamble_length,2)))-1)*np.sqrt(2)/2\n",
    "    # add AWG noise to the preamble\n",
    "    if snr > 0:\n",
    "        preamble_noisy = (1./np.sqrt(snr)) * np.random.randn(preamble_length,2)+preamble_test_orig[i,:,:]\n",
    "    \n",
    "    # rotate data according to cfo\n",
    "    for j in range(preamble_length):\n",
    "        preamble_test_cfo[i,j,0]=(preamble_noisy[j,0]*np.cos(omega_test[i]*j)\n",
    "                                       -preamble_noisy[j,1]*np.sin(omega_test[i]*j))\n",
    "        preamble_test_cfo[i,j,1]=(preamble_noisy[j,0]*np.sin(omega_test[i]*j)\n",
    "                                      +preamble_noisy[j,1]*np.cos(omega_test[i]*j))\n",
    "\n",
    "print(\"Data generation complete.\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "# print(\"Original preamble\")\n",
    "# print(preamble_train_orig[num_train-1,:,:])\n",
    "# print(\"Noisy preamble\")\n",
    "# print(preamble_noisy)\n",
    "# print(\"CFO preamble\")\n",
    "# print(preamble_train_cfo[num_train-1,:,:])\n",
    "# print(\"rate of cfo\")\n",
    "# print(omega_train[num_train-1])\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Feedforward Neural Network to find omega\n",
    "import tensorflow as tf\n",
    "\n",
    "# tf.enable_eager_execution()\n",
    "\n",
    "learning_rate = 0.01\n",
    "\n",
    "# declare the training data placeholders\n",
    "preamble_original = tf.placeholder(tf.float32, [None, preamble_length, 2])\n",
    "preamble_cfo = tf.placeholder(tf.float32, [None, preamble_length, 2])\n",
    "omega = tf.placeholder(tf.float32, [None,1])\n",
    "\n",
    "preamble_original_cfo = tf.concat([preamble_original, preamble_cfo], 1)\n",
    "\n",
    "preamble_original_cfo_flat = tf.contrib.layers.flatten(preamble_original_cfo)\n",
    "\n",
    "layer_1 = tf.layers.dense(\n",
    "  preamble_original_cfo_flat, 10, tf.nn.sigmoid, use_bias=True)\n",
    "layer_2 = tf.layers.dense(\n",
    "  layer_1, 10, tf.nn.sigmoid, use_bias=True)\n",
    "layer_3 = tf.layers.dense(\n",
    "  layer_2, 1, activation=tf.identity, use_bias=True)\n",
    "\n",
    "est_omega = layer_3\n",
    "\n",
    "preamble_cfo_complex = tf.complex(preamble_cfo[:,:,0], preamble_cfo[:,:,1])\n",
    "preamble_cfo_complex = tf.expand_dims(preamble_cfo_complex, -1)\n",
    "\n",
    "# build the rotation matrix\n",
    "incremented_omega = []\n",
    "for i in range(preamble_length):\n",
    "    incremented_omega.append(-est_omega*i)\n",
    "\n",
    "rotation_complex = tf.exp(tf.complex(0.0,tf.transpose(incremented_omega, perm=[1,0,2])))\n",
    "preamble_rotated_complex = tf.multiply(preamble_cfo_complex,rotation_complex)\n",
    "\n",
    "preamble_rotated = tf.stack([tf.real(preamble_rotated_complex[:,:]), \n",
    "                             tf.imag(preamble_rotated_complex[:,:])], axis=2)\n",
    "\n",
    "preamble_rotated = tf.squeeze(preamble_rotated)\n",
    "\n",
    "estimation_loss = tf.losses.mean_squared_error(preamble_original, preamble_rotated)\n",
    "\n",
    "omega_loss = tf.losses.mean_squared_error(est_omega,omega)\n",
    "\n",
    "optimizer = tf.train.AdamOptimizer(learning_rate).minimize(estimation_loss)\n",
    "                                                                                  \n",
    "# finally setup the initialisation operator\n",
    "init_op = tf.global_variables_initializer()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 0, Train Cost 1.015472650527954, Test Cost: 0.8811811804771423\n",
      "Epoch 100, Train Cost 0.04622652009129524, Test Cost: 0.033472348004579544\n",
      "Epoch 200, Train Cost 0.03762116655707359, Test Cost: 0.03413495793938637\n",
      "Epoch 300, Train Cost 0.0383332334458828, Test Cost: 0.03510737791657448\n",
      "Epoch 400, Train Cost 0.06767338514328003, Test Cost: 0.045283298939466476\n",
      "Epoch 500, Train Cost 0.04421050846576691, Test Cost: 0.038330186158418655\n",
      "Epoch 600, Train Cost 0.048845428973436356, Test Cost: 0.03421986475586891\n",
      "Epoch 700, Train Cost 0.05553166940808296, Test Cost: 0.06988056749105453\n",
      "Epoch 800, Train Cost 0.029462121427059174, Test Cost: 0.04390124976634979\n",
      "Epoch 900, Train Cost 0.031773291528224945, Test Cost: 0.06190149486064911\n",
      "Epoch 1000, Train Cost 0.029868530109524727, Test Cost: 0.02910785563290119\n",
      "Epoch 1100, Train Cost 0.031890351325273514, Test Cost: 0.03130427002906799\n",
      "Epoch 1200, Train Cost 0.027978356927633286, Test Cost: 0.028210613876581192\n",
      "Epoch 1300, Train Cost 0.030985480174422264, Test Cost: 0.038058992475271225\n",
      "Epoch 1400, Train Cost 0.027035046368837357, Test Cost: 0.02736923284828663\n",
      "Epoch 1500, Train Cost 0.02972193993628025, Test Cost: 0.04954095557332039\n",
      "Epoch 1600, Train Cost 0.03176096826791763, Test Cost: 0.02760952152311802\n",
      "Epoch 1700, Train Cost 0.03257650509476662, Test Cost: 0.0272685419768095\n",
      "Epoch 1800, Train Cost 0.03004729375243187, Test Cost: 0.036179814487695694\n",
      "Epoch 1900, Train Cost 0.0282842218875885, Test Cost: 0.029944470152258873\n",
      "Epoch 2000, Train Cost 0.024018211290240288, Test Cost: 0.023251311853528023\n",
      "Epoch 2100, Train Cost 0.02671871893107891, Test Cost: 0.025560244917869568\n",
      "Epoch 2200, Train Cost 0.02509189024567604, Test Cost: 0.02379639260470867\n",
      "Epoch 2300, Train Cost 0.03252383694052696, Test Cost: 0.024785812944173813\n",
      "Epoch 2400, Train Cost 0.02545705810189247, Test Cost: 0.023191537708044052\n",
      "Epoch 2500, Train Cost 0.023910043761134148, Test Cost: 0.02340712770819664\n",
      "Epoch 2600, Train Cost 0.034405048936605453, Test Cost: 0.032284390181303024\n",
      "Epoch 2700, Train Cost 0.026409145444631577, Test Cost: 0.024714022874832153\n",
      "Epoch 2800, Train Cost 0.023222269490361214, Test Cost: 0.026636309921741486\n",
      "Epoch 2900, Train Cost 0.0215096864849329, Test Cost: 0.023204857483506203\n",
      "Epoch 3000, Train Cost 0.02384386770427227, Test Cost: 0.02288980968296528\n",
      "Epoch 3100, Train Cost 0.02235761098563671, Test Cost: 0.021961823105812073\n",
      "Epoch 3200, Train Cost 0.02349221147596836, Test Cost: 0.02341875620186329\n",
      "Epoch 3300, Train Cost 0.023050393909215927, Test Cost: 0.02882535010576248\n",
      "Epoch 3400, Train Cost 0.0268245879560709, Test Cost: 0.022743789479136467\n",
      "Epoch 3500, Train Cost 0.025811485946178436, Test Cost: 0.024038590490818024\n",
      "Epoch 3600, Train Cost 0.024861082434654236, Test Cost: 0.030605526641011238\n",
      "Epoch 3700, Train Cost 0.02393897995352745, Test Cost: 0.022190937772393227\n",
      "Epoch 3800, Train Cost 0.027283379808068275, Test Cost: 0.02267160825431347\n",
      "Epoch 3900, Train Cost 0.024986134842038155, Test Cost: 0.02251618728041649\n",
      "Epoch 4000, Train Cost 0.024150075390934944, Test Cost: 0.021905919536948204\n",
      "Epoch 4100, Train Cost 0.02213907428085804, Test Cost: 0.022219479084014893\n",
      "Epoch 4200, Train Cost 0.023062802851200104, Test Cost: 0.027661336585879326\n",
      "Epoch 4300, Train Cost 0.023022674024105072, Test Cost: 0.022261206060647964\n",
      "Epoch 4400, Train Cost 0.02375992387533188, Test Cost: 0.021952254697680473\n",
      "Epoch 4500, Train Cost 0.02771276794373989, Test Cost: 0.023583509027957916\n",
      "Epoch 4600, Train Cost 0.028416022658348083, Test Cost: 0.025391835719347\n",
      "Epoch 4700, Train Cost 0.03235162794589996, Test Cost: 0.02201882377266884\n",
      "Epoch 4800, Train Cost 0.023995215073227882, Test Cost: 0.022086746990680695\n",
      "Epoch 4900, Train Cost 0.02406725473701954, Test Cost: 0.02358872815966606\n",
      "Epoch 5000, Train Cost 0.024906011298298836, Test Cost: 0.022539613768458366\n",
      "Epoch 5100, Train Cost 0.023286981508135796, Test Cost: 0.022230451926589012\n",
      "Epoch 5200, Train Cost 0.022808585315942764, Test Cost: 0.0231722891330719\n",
      "Epoch 5300, Train Cost 0.03380690515041351, Test Cost: 0.029903357848525047\n",
      "Epoch 5400, Train Cost 0.024402864277362823, Test Cost: 0.023835361003875732\n",
      "Epoch 5500, Train Cost 0.025190720334649086, Test Cost: 0.02249654196202755\n",
      "Epoch 5600, Train Cost 0.02225024625658989, Test Cost: 0.02391267940402031\n",
      "Epoch 5700, Train Cost 0.02648526057600975, Test Cost: 0.024167807772755623\n",
      "Epoch 5800, Train Cost 0.022575128823518753, Test Cost: 0.028253454715013504\n",
      "Epoch 5900, Train Cost 0.024648014456033707, Test Cost: 0.02257273904979229\n",
      "Epoch 6000, Train Cost 0.039224639534950256, Test Cost: 0.024897124618291855\n",
      "Epoch 6100, Train Cost 0.023564979434013367, Test Cost: 0.033722758293151855\n",
      "Epoch 6200, Train Cost 0.022543590515851974, Test Cost: 0.021386224776506424\n",
      "Epoch 6300, Train Cost 0.023851050063967705, Test Cost: 0.02268531545996666\n",
      "Epoch 6400, Train Cost 0.022296614944934845, Test Cost: 0.02257997915148735\n",
      "Epoch 6500, Train Cost 0.02220727689564228, Test Cost: 0.02224726229906082\n",
      "Epoch 6600, Train Cost 0.023666653782129288, Test Cost: 0.023115454241633415\n",
      "Epoch 6700, Train Cost 0.024312715977430344, Test Cost: 0.022206097841262817\n",
      "Epoch 6800, Train Cost 0.021594718098640442, Test Cost: 0.021248536184430122\n",
      "Epoch 6900, Train Cost 0.02262623980641365, Test Cost: 0.02357776276767254\n",
      "Epoch 7000, Train Cost 0.021883081644773483, Test Cost: 0.022093364968895912\n",
      "Epoch 7100, Train Cost 0.024097997695207596, Test Cost: 0.027463208884000778\n",
      "Epoch 7200, Train Cost 0.022731661796569824, Test Cost: 0.021907398477196693\n",
      "Epoch 7300, Train Cost 0.024224255234003067, Test Cost: 0.02311108075082302\n",
      "Epoch 7400, Train Cost 0.023677045479416847, Test Cost: 0.021979670971632004\n",
      "Epoch 7500, Train Cost 0.023996058851480484, Test Cost: 0.021545642986893654\n",
      "Epoch 7600, Train Cost 0.02412448078393936, Test Cost: 0.021760854870080948\n",
      "Epoch 7700, Train Cost 0.02153320051729679, Test Cost: 0.021380849182605743\n",
      "Epoch 7800, Train Cost 0.02307840809226036, Test Cost: 0.021802932024002075\n",
      "Epoch 7900, Train Cost 0.02369779162108898, Test Cost: 0.023801080882549286\n",
      "Epoch 8000, Train Cost 0.024109527468681335, Test Cost: 0.028249964118003845\n",
      "Epoch 8100, Train Cost 0.021932490170001984, Test Cost: 0.0225493386387825\n",
      "Epoch 8200, Train Cost 0.02353687398135662, Test Cost: 0.023480532690882683\n",
      "Epoch 8300, Train Cost 0.022826258093118668, Test Cost: 0.023374509066343307\n",
      "Epoch 8400, Train Cost 0.04437744617462158, Test Cost: 0.060331810265779495\n",
      "Epoch 8500, Train Cost 0.026767639443278313, Test Cost: 0.022334566339850426\n",
      "Epoch 8600, Train Cost 0.02205980010330677, Test Cost: 0.022154347971081734\n",
      "Epoch 8700, Train Cost 0.02445625700056553, Test Cost: 0.023730849847197533\n",
      "Epoch 8800, Train Cost 0.02349151484668255, Test Cost: 0.021484751254320145\n",
      "Epoch 8900, Train Cost 0.02233005128800869, Test Cost: 0.02171524055302143\n",
      "Epoch 9000, Train Cost 0.02588682249188423, Test Cost: 0.02531522512435913\n",
      "Epoch 9100, Train Cost 0.02178703062236309, Test Cost: 0.021226076409220695\n",
      "Epoch 9200, Train Cost 0.021555330604314804, Test Cost: 0.02148973010480404\n",
      "Epoch 9300, Train Cost 0.025440076366066933, Test Cost: 0.026425695046782494\n",
      "Epoch 9400, Train Cost 0.023374048992991447, Test Cost: 0.022468047216534615\n",
      "Epoch 9500, Train Cost 0.02242165058851242, Test Cost: 0.02284381352365017\n",
      "Epoch 9600, Train Cost 0.022709054872393608, Test Cost: 0.024100296199321747\n",
      "Epoch 9700, Train Cost 0.024385178461670876, Test Cost: 0.021855676546692848\n",
      "Epoch 9800, Train Cost 0.022596238180994987, Test Cost: 0.023639826104044914\n",
      "Epoch 9900, Train Cost 0.022721581161022186, Test Cost: 0.022499410435557365\n"
     ]
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7f92a97d9d68>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.figure()\n",
    "\n",
    "# start the session\n",
    "with tf.Session() as sess:\n",
    "    #    initialize the variables\n",
    "    sess.run(init_op)\n",
    "    mc_losses = []\n",
    "    \n",
    "    for epoch in range(epochs):\n",
    "        \n",
    "        current_start = epoch*batch_size\n",
    "        preamble_train_orig_batch = preamble_train_orig[current_start:(current_start+batch_size),:,:]\n",
    "        preamble_train_cfo_batch = preamble_train_cfo[current_start:(current_start+batch_size),:,:]\n",
    "        omega_train_batch = omega_train[current_start:(current_start+batch_size),:]\n",
    "\n",
    "        _,cost,est_omega_batch, omega_cost = sess.run([optimizer, estimation_loss, est_omega, omega_loss], \n",
    "                                          feed_dict={preamble_original: preamble_train_orig_batch, \n",
    "                                                    preamble_cfo: preamble_train_cfo_batch,\n",
    "                                                    omega: omega_train_batch})    \n",
    "\n",
    "        if epoch % 100 == 0: \n",
    "            \n",
    "            mc_cost, mc_omega_cost, mc_est_omega,mc_corrected = sess.run([estimation_loss, \n",
    "                                                                          omega_loss,est_omega,\n",
    "                                                                          preamble_rotated], \n",
    "                                             feed_dict={preamble_original: preamble_test_orig,\n",
    "                                                        preamble_cfo: preamble_test_cfo,\n",
    "                                                       omega: omega_test})\n",
    "            \n",
    "            \n",
    "#             plt.plot(epoch, mc_cost, 'bo')\n",
    "#             plt.plot(epoch, zero_force_error, 'ro')\n",
    "#             plt.plot(epoch, mse_error, 'go')\n",
    "            print('Epoch {}, Train Cost {}, Test Cost: {}'.format(epoch, cost, mc_cost))\n",
    "            plt.plot(epoch,np.log(mc_cost),'go')\n",
    "            plt.plot(epoch,np.log(mc_omega_cost),'ro')\n",
    "#             print('Epoch {}, Train Cost {}'.format(epoch, cost))\n",
    "    \n",
    "    \n",
    "    plt.xlabel('Training Epoch')\n",
    "    plt.ylabel('L2 Test Cost')\n",
    "    plt.title('NN Equalizer: no noise')\n",
    "    # plt.text(1000, .025, r'NN equalizer')\n",
    "    # plt.text(0.5, .025, r'Zero Force equalizer')\n",
    "    plt.show()\n",
    "    \n",
    "    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7f92a8e9ffd0>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import numpy as np\n",
    "import scipy.signal as sig\n",
    "from numpy import linalg as LA\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "plt.figure()\n",
    "# plot unit circle\n",
    "t = np.linspace(0,np.pi*2,100)\n",
    "plt.plot(np.cos(t), np.sin(t), linewidth=1)\n",
    "\n",
    "k = 26\n",
    "j = 49\n",
    "\n",
    "# plot original point\n",
    "plt.plot(preamble_test_orig[k,j,0], preamble_test_orig[k,j,1], 'go')\n",
    "\n",
    "# plot CFO point\n",
    "plt.plot(preamble_test_cfo[k,j,0], preamble_test_cfo[k,j,1], 'ro')\n",
    "\n",
    "# plot rotated point\n",
    "plt.plot(mc_corrected[k,j,0], mc_corrected[k,j,1], 'bo')\n",
    "\n",
    "plt.gca().set_aspect('equal', adjustable='box')\n",
    "plt.show()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
